﻿using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LiveGame
{
    public class Cell : IPieces
    {
        public Cell( bool status, int row, int column )
        {
            // TODO: Complete member initialization
            this.Status = status;
            this.TempStatus = status;
            this.Row = row;
            this.Column = column;
            this.Neighbors = new Neighbor();
        }

        public    bool     Status     { get; private set; }
        public    bool     TempStatus { get; private set; }
        public    int      Row        { get; private set; }
        public    int      Column     { get; private set; }
        protected Neighbor Neighbors  { get; set; }

        protected int NumberOfLiveNeighbors 
        {
            get
            {
                var numberOfLiveNeighbors = 0;

                foreach( var neighbor in this.Neighbors )
                    if( neighbor.Status == true )
                        numberOfLiveNeighbors++;

                return numberOfLiveNeighbors;
            }
        }

        public void Add( Cell neighbor )
        {
            if( neighbor == null )
                throw  new ArgumentNullException( "neighbor" );

            try
            {
                this.Neighbors.Add( neighbor );
            }
            catch( ArgumentOutOfRangeException exception )
            {
                throw new ArgumentOutOfRangeException( "neighbor cannot be null", exception );
            }
        }
        
        /// <summary>
        /// Calculates the status next generation of itself, 
        /// but does not change the status of itself. 
        /// To change the status, call ApplyResult()
        /// </summary>
        public void Execute()
        {
            if( this.Status == true )
                this.ApplyRulesForLiveStatus();

            this.ApplyRulesForDeadStatus();
        }

        /// <summary>
        /// Change the status for the next generation of this cell.
        /// No changes applied, if Execute() method is not invoked prior
        /// to this function. 
        /// Execute() method has to be invoked before this
        /// method to calculate the status of the next generation of this cell.
        /// </summary>
        public void ApplyResult()
        {
            this.Status = this.TempStatus;
        }

        /// <summary>
        /// There are 3 rules to be applied for if this cell status is alive:
        /// 
        /// 1. Under population, i.e. Less than 2 live neighbors, dies
        /// 2. Overcrowding, i.e. More than 3 live neighbors, dies
        /// 3. LongLive, ie. Within 2 - 3 live neighbors, lives on to next generation
        /// </summary>
        private void ApplyRulesForLiveStatus()
        {
            if( this.IsUnderpopulation() == true )
            {
                this.TempStatus = false;
                return;
            }

            if( this.IsOverCrowding() == true )
            {
                this.TempStatus = false;
                return;
            }
        }

        /// <summary>
        /// More than 3 live neighbors, dies
        /// </summary>
        /// <returns></returns>
        private bool IsOverCrowding()
        {
            if( this.NumberOfLiveNeighbors > 3 )
                return true;
            return false;
        }

        /// <summary>
        /// Less than 2 live neighbors, dies
        /// </summary>
        /// <returns></returns>
        private bool IsUnderpopulation()
        {
            if( this.NumberOfLiveNeighbors < 2 )
                return true;
            return false;
        }

        /// <summary>
        /// Applies the following rules if this cell status is dead:
        /// 
        /// 1. Dead cell with exactly 3 live neighbors, becomes a live cell
        /// </summary>
        private void ApplyRulesForDeadStatus()
        {
            if( this.IsRevived() == true )
                this.TempStatus = true;
        }

        /// <summary>
        /// Dead cell with exactly 3 live neighbors, becomes a live cell
        /// </summary>
        /// <returns></returns>
        private bool IsRevived()
        {
            if( this.NumberOfLiveNeighbors == 3 )
                return true;
            return false;
        }
    }
}
